package ling.archives.common;

import com.ruoyi.common.annotation.Excel;
import com.ruoyi.common.core.text.Convert;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.file.FileUtils;
import com.ruoyi.common.utils.poi.ExcelHandlerAdapter;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.common.utils.reflect.ReflectUtils;
import lombok.var;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.util.IOUtils;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.*;

public class ExcelUtilEx<T> extends ExcelUtil<T> {
    public ExcelUtilEx(Class<T> clazz) {
        super(clazz);
    }
    public <K> ExcelUtilEx<K> newByWorkbook(Class<K> clazz){
        var n= new ExcelUtilEx<>(clazz);
        n.wb=wb;
        return n;
    }
    @Override
    public List<T> importExcel(String sheetName, InputStream is, int titleNum) throws Exception {
        try {
            wb = WorkbookFactory.create(is);
            return importExcel(sheetName, wb, titleNum);
        } finally {
            IOUtils.closeQuietly(is);
        }
    }

    public List<T> importExcel(String sheetName, int titleNum) throws Exception {
        return importExcel(sheetName, wb, titleNum);
    }
    protected List<T> importExcel(String sheetName, Workbook wb, int titleNum) throws Exception {
        //this.type = Excel.Type.IMPORT;
        //wb=WorkbookFactory.create(is);
        List<T> list = new ArrayList<T>();
        // 如果指定sheet名,则取指定sheet中的内容 否则默认指向第1个sheet
        Sheet sheet = StringUtils.isNotEmpty(sheetName) ? wb.getSheet(sheetName) : wb.getSheetAt(0);
        if (sheet == null)
        {
            throw new IOException("文件sheet不存在");
        }
        boolean isXSSFWorkbook = !(wb instanceof HSSFWorkbook);
        Map<String, PictureData> pictures;
        if (isXSSFWorkbook)
        {
            pictures = getSheetPictures07((XSSFSheet) sheet, (XSSFWorkbook) wb);
        }
        else
        {
            pictures = getSheetPictures03((HSSFSheet) sheet, (HSSFWorkbook) wb);
        }
        // 获取最后一个非空行的行下标，比如总行数为n，则返回的为n-1
        int rows = sheet.getLastRowNum();
        if (rows > 0)
        {
            // 定义一个map用于存放excel列的序号和field.
            Map<String, Integer> cellMap = new HashMap<String, Integer>();
            // 获取表头
            Row heard = sheet.getRow(titleNum);
            for (int i = 0; i < heard.getPhysicalNumberOfCells(); i++)
            {
                Cell cell = heard.getCell(i);
                if (StringUtils.isNotNull(cell))
                {
                    String value = this.getCellValue(heard, i).toString();
                    cellMap.put(value, i);
                }
                else
                {
                    cellMap.put(null, i);
                }
            }
            // 有数据时才处理 得到类的所有field.
            List<Object[]> fields = this.getFields();
            Map<Integer, Object[]> fieldsMap = new HashMap<Integer, Object[]>();
            Integer fIndex=-1;
            for (Object[] objects : fields)
            {
                Excel attr = (Excel) objects[1];
                Integer column = cellMap.get(attr.name());
                if (column != null)
                {
                    fieldsMap.put(column, objects);
                }else
                    fieldsMap.put(fIndex, objects);
                fIndex--;

            }
            for (int i = titleNum + 1; i <= rows; i++) {
                // 从第2行开始取数据,默认第一行是表头.
                Row row = sheet.getRow(i);
                // 判断当前行是否是空行
                if (isRowEmpty(row)) {
                    continue;
                }
                T entity = gainData(fieldsMap, row, pictures);
                list.add(entity);
                if (entity instanceof ExcelHandle.rowSetHeader)
                    ((ExcelHandle.rowSetHeader) entity).after(row);
            }
        }
        return list;
    }

    private T gainData(Map<Integer, Object[]> fieldsMap, Row row, Map<String, PictureData> pictures) throws InstantiationException, IllegalAccessException, IOException {
        T entity = null;
        for (Map.Entry<Integer, Object[]> entry : fieldsMap.entrySet())
        {
            if(entry.getKey()<0)
            {
                continue;
            }
            Object val = this.getCellValue(row, entry.getKey());

            // 如果不存在实例则新建.
            entity = (entity == null ? clazz.newInstance() : entity);
            // 从map中得到对应列的field.
            Field field = (Field) entry.getValue()[0];
            Excel attr = (Excel) entry.getValue()[1];
            // 取得类型,并根据对象类型设置值.
            Class<?> fieldType = field.getType();
            if (String.class == fieldType)
            {
                String s = Convert.toStr(val);
                if (StringUtils.endsWith(s, ".0"))
                {
                    val = StringUtils.substringBefore(s, ".0");
                }
                else
                {
                    String dateFormat = field.getAnnotation(Excel.class).dateFormat();
                    if (StringUtils.isNotEmpty(dateFormat))
                    {
                        val = parseDateToStr(dateFormat, val);
                    }
                    else
                    {
                        val = Convert.toStr(val);
                    }
                }
            }
            else if ((Integer.TYPE == fieldType || Integer.class == fieldType) && StringUtils.isNumeric(Convert.toStr(val)))
            {
                val = Convert.toInt(val);
            }
            else if ((Long.TYPE == fieldType || Long.class == fieldType) && StringUtils.isNumeric(Convert.toStr(val)))
            {
                val = Convert.toLong(val);
            }
            else if (Double.TYPE == fieldType || Double.class == fieldType)
            {
                val = Convert.toDouble(val);
            }
            else if (Float.TYPE == fieldType || Float.class == fieldType)
            {
                val = Convert.toFloat(val);
            }
            else if (BigDecimal.class == fieldType)
            {
                val = Convert.toBigDecimal(val);
            }
            else if (Date.class == fieldType)
            {
                if (val instanceof String)
                {
                    val = DateUtils.parseDate(val);
                }
                else if (val instanceof Double)
                {
                    val = DateUtil.getJavaDate((Double) val);
                }
            }
            else if (Boolean.TYPE == fieldType || Boolean.class == fieldType)
            {
                val = Convert.toBool(val, false);
            }
            if (StringUtils.isNotNull(fieldType))
            {
                String propertyName = field.getName();
                if (StringUtils.isNotEmpty(attr.targetAttr()))
                {
                    propertyName = field.getName() + "." + attr.targetAttr();
                }
                if (StringUtils.isNotEmpty(attr.readConverterExp()))
                {
                    val = reverseByExp(Convert.toStr(val), attr.readConverterExp(), attr.separator());
                }
                else if (StringUtils.isNotEmpty(attr.dictType()))
                {
                    if (!sysDictMap.containsKey(attr.dictType() + val))
                    {
                        String dictValue = reverseDictByExp(Convert.toStr(val), attr.dictType(), attr.separator());
                        sysDictMap.put(attr.dictType() + val, dictValue);
                    }
                    val = sysDictMap.get(attr.dictType() + val);
                }
                else if (!attr.handler().equals(ExcelHandlerAdapter.class))
                {
                    val = dataFormatHandlerAdapter(val, attr, row.getCell(entry.getKey()));
                }
                else if (Excel.ColumnType.IMAGE == attr.cellType() && StringUtils.isNotEmpty(pictures))
                {
                    PictureData image = pictures.get(row.getRowNum() + "_" + entry.getKey());
                    if (image == null)
                    {
                        val = "";
                    }
                    else
                    {
                        byte[] data = image.getData();
                        val = FileUtils.writeImportBytes(data);
                    }
                }
                ReflectUtils.invokeSetter(entity, propertyName, val);
            }
        }
        return entity;
    }

    /**
     * 判断是否是空行
     *
     * @param row 判断的行
     * @return
     */
    protected boolean isRowEmpty(Row row)
    {
        if (row == null)
        {
            return true;
        }
        for (int i = row.getFirstCellNum(); i < row.getLastCellNum(); i++)
        {
            Cell cell = row.getCell(i);
            if (cell != null && cell.getCellType() != CellType.BLANK)
            {
                return false;
            }
        }
        return true;
    }
}
